隨著比特幣接近主流采用和認(rèn)可,其以挖礦為特征的基本安全模型每天都受到越來越多的關(guān)注和審查。人們?cè)絹碓疥P(guān)注和關(guān)注比特幣挖礦對(duì)環(huán)境的影響、底層模型的安全性和去中心化程度,甚至量子計(jì)算突破對(duì)比特幣和其他加密貨幣未來的潛在影響。
很多時(shí)候,工作量證明被描述為“密碼學(xué)難題”,但真正的難題是什么?為了真正理解這些問題(以及任何可能的答案),您需要對(duì)比特幣挖礦本身及其演變有一個(gè)基本的了解。本文將探討工作量證明的所有技術(shù)組件和移動(dòng)部分,以及它們?nèi)绾蜗嗷o縫同步以使比特幣成為今天的去中心化平臺(tái)。
為什么挖礦有效:加密單向哈希
比特幣區(qū)塊鏈通常被描述為加密安全的數(shù)據(jù)庫,因此是不可變的。支持這種不變性和安全性的底層技術(shù)是加密哈希。密碼散列函數(shù)是一種數(shù)學(xué)函數(shù),簡(jiǎn)單地說,它接受任何輸入并將其映射到固定大小的字符串。
然而,這些函數(shù)有四個(gè)特殊屬性,使它們對(duì)比特幣網(wǎng)絡(luò)非常寶貴。他們是:
- 確定性——對(duì)于加密散列函數(shù)的任何輸入,結(jié)果輸出將始終相同。
- 快速——在給定任何輸入的情況下,計(jì)算散列函數(shù)的輸出是一個(gè)相對(duì)較快的過程(不需要大量計(jì)算)
- 唯一——函數(shù)的每個(gè)輸入都應(yīng)該產(chǎn)生一個(gè)完全隨機(jī)且唯一的輸出(換句話說,沒有兩個(gè)輸入會(huì)產(chǎn)生相同的輸出)
- 不可逆——給定哈希函數(shù)的輸出,無法獲得原始輸入
這些規(guī)則為比特幣挖礦保護(hù)網(wǎng)絡(luò)提供了基礎(chǔ)。
特別是比特幣協(xié)議的創(chuàng)建者中本聰選擇使用SHA-256 哈希函數(shù)作為比特幣挖礦的基礎(chǔ)。這是一個(gè)特定的密碼散列函數(shù),已在數(shù)學(xué)上證明具有上述屬性。它總是輸出一個(gè)256 位的數(shù)字(最基本的計(jì)算單位),通常以 64 個(gè)字符的十六進(jìn)制數(shù)字系統(tǒng)表示,以方便人類閱讀。
SHA-256 函數(shù)的輸出通常稱為其輸入的哈希值。

哈希函數(shù)的輸入導(dǎo)致完全唯一的輸出
這是一個(gè) SHA-256 函數(shù)輸入和輸出的示例(您可以在這里自己嘗試一下):
Input to SHA-256:
<Bitcoin Transaction>
Output to SHA-256:
77077b1f4c3ad44c83dc0bdb8d937e9b71c0ef07a35c2664bb7da85be738eacf
有趣的是,在比特幣協(xié)議中使用散列的大多數(shù)地方,都使用了雙重散列。這意味著原始 SHA-256 函數(shù)的輸出隨后會(huì)直接放回 SHA-256 函數(shù)以獲得另一個(gè)輸出。這是該過程的樣子:
Input to SHA-256(first round):
<Bitcoin Transaction>
Output (first round):
77077b1f4c3ad44c83dc0bdb8d937e9b71c0ef07a35c2664bb7da85be738eacf
Input to SHA-256 (second round):
77077b1f4c3ad44c83dc0bdb8d937e9b71c0ef07a35c2664bb7da85be738eacf
Output (second round and final result):
3c6c55b0e4b607b672b50f04e028a6951aed6dc97b91e103fb0f348c3f1dfa00
雙重哈希用于防止生日攻擊。生日攻擊是一種攻擊者能夠通過使用完全不同的輸入(稱為沖突)產(chǎn)生與另一個(gè)輸入相同的哈希的場(chǎng)景。這打破了唯一性的第三個(gè)屬性。沒有它,兩個(gè)完全不同的比特幣區(qū)塊可能會(huì)由完全相同的哈希表示,從而允許攻擊者潛在地切換區(qū)塊。
使用 SHA-256 函數(shù),這種攻擊發(fā)生的概率無限小。如果不是幾乎不可能,SHA-256 將被視為已損壞。
然而,其他散列函數(shù)在過去已經(jīng)被“破壞”了。為了防止 SHA-256 將來發(fā)生這種情況(并有效地破壞比特幣的安全模型),最好對(duì)hash 進(jìn)行哈希處理。這將發(fā)生沖突的可能性減半,使協(xié)議更加安全。
在非常高的水平上,比特幣挖礦是一個(gè)系統(tǒng),其中所有比特幣交易都發(fā)送給比特幣礦工。礦工選擇價(jià)值 1 兆字節(jié)的交易,將它們捆綁為 SHA-256 函數(shù)的輸入,并嘗試找到網(wǎng)絡(luò)接受的特定輸出。第一個(gè)找到此輸出并將區(qū)塊發(fā)布到網(wǎng)絡(luò)的礦工會(huì)以交易費(fèi)用和新比特幣的創(chuàng)建形式獲得獎(jiǎng)勵(lì)。讓我們更進(jìn)一步,深入了解比特幣區(qū)塊鏈本身,看看礦工究竟做了什么來確保網(wǎng)絡(luò)安全。
比特幣挖礦:技術(shù)介紹
引入挖礦是為了解決雙花問題。如果我有 1 個(gè)比特幣并將其發(fā)送給 Bob,然后嘗試將相同的比特幣發(fā)送給 Alice,網(wǎng)絡(luò)會(huì)確保只接受一筆交易。它通過稱為采礦的眾所周知的過程來做到這一點(diǎn)。
在深入研究技術(shù)細(xì)節(jié)之前,重要的是要了解為什么需要挖礦來保護(hù)網(wǎng)絡(luò)。由于現(xiàn)在存在法定貨幣,我們持有的貨幣是由美聯(lián)儲(chǔ)創(chuàng)建和驗(yàn)證的。由于比特幣在去中心化和共識(shí)的嚴(yán)格假設(shè)下運(yùn)作,因此不存在任何中央機(jī)構(gòu)來驗(yàn)證該貨幣的發(fā)行并為其加蓋時(shí)間戳以及對(duì)該貨幣發(fā)生的任何交易的驗(yàn)證。
Satoshi Nakamoto 提出了當(dāng)時(shí)唯一已知的解決方案,以在面向共識(shí)的系統(tǒng)中解決此驗(yàn)證問題。這個(gè)方案在比特幣白皮書中被稱為工作量證明,它優(yōu)雅地證明了交易是由那些愿意花費(fèi)足夠的物理計(jì)算能量和時(shí)間來進(jìn)行驗(yàn)證的人驗(yàn)證的,同時(shí)引入了誘導(dǎo)市場(chǎng)競(jìng)爭(zhēng)的激勵(lì)措施。這種競(jìng)爭(zhēng)使去中心化的特性能夠在生態(tài)系統(tǒng)中有機(jī)地出現(xiàn)和繁榮。
塊內(nèi)的外觀
一個(gè)比特幣區(qū)塊主要由兩個(gè)部分組成:
1.交易,以默克爾樹的形式
采礦計(jì)算機(jī)收集足夠的交易來填充一個(gè)塊并將它們捆綁到一個(gè)默克爾樹中。
merkle 樹是一個(gè)相對(duì)簡(jiǎn)單的概念:交易作為葉子位于樹的底部,并使用 SHA-256 函數(shù)進(jìn)行哈希處理。使用 SHA-256 函數(shù)再次對(duì)兩個(gè)葉子事務(wù)的組合進(jìn)行哈希處理,以形成葉子的父節(jié)點(diǎn)。這個(gè)父節(jié)點(diǎn)與散列交易的其他父節(jié)點(diǎn)一起不斷向上哈希,直到創(chuàng)建一個(gè)根。這個(gè)根的哈希實(shí)際上是它下面的交易的唯一表示。

默克爾樹的根是樹中每個(gè)交易的哈希值的組合。回想一下,對(duì)于散列函數(shù)的任何輸入,輸出都是完全唯一的。因此,一旦網(wǎng)絡(luò)上的大多數(shù)節(jié)點(diǎn)接收到一個(gè)挖掘的塊,默克爾樹哈希的根就充當(dāng)該給定塊中所有交易的不可更改的摘要。
如果惡意行為者嘗試更改塊中交易的內(nèi)容,則其哈希值將被更改。哈希的這種變化將向上傳播到交易的默克爾樹,直到根的哈希改變。然后,任何節(jié)點(diǎn)都可以通過將更改塊的默克爾樹的根與有效塊的默克爾樹的根進(jìn)行比較來快速捕捉到這種惡意行為。
2.區(qū)塊頭
區(qū)塊頭是區(qū)塊本身內(nèi)容的摘要。它包含以下六個(gè)組件:
- 比特幣客戶端運(yùn)行的軟件版本
- 區(qū)塊的時(shí)間戳
- 其包含交易的默克爾樹的根
- 它之前的塊的哈希
- 一個(gè)隨機(jī)數(shù)
- 目標(biāo)_
請(qǐng)記住,交易默克爾樹的根充當(dāng)區(qū)塊中每筆交易的有效摘要,而無需查看每筆交易。前一個(gè)塊的散列允許網(wǎng)絡(luò)按時(shí)間順序正確放置塊。這就是術(shù)語區(qū)塊鏈的來源——每個(gè)區(qū)塊都鏈接到前一個(gè)區(qū)塊。隨機(jī)數(shù)和目標(biāo)是挖礦的關(guān)鍵。它們是解決礦工需要解決的 SHA-256 難題的基礎(chǔ)。
請(qǐng)注意,塊頭中的所有這些數(shù)據(jù)都使用一種稱為little-endian的符號(hào)壓縮成 80 個(gè)字節(jié),這使得節(jié)點(diǎn)之間的塊頭傳輸變得非常高效。出于解釋的目的,我們將忽略這種壓縮并假設(shè)數(shù)據(jù)是其原始形式。
解釋采礦問題
存儲(chǔ)在塊頭中的目標(biāo)只是一個(gè)存儲(chǔ)在位中的數(shù)值。在傳統(tǒng)的以 10 為底的表示法中,這個(gè)目標(biāo)的范圍在 0 到 222?(一個(gè)67 位以上?的數(shù)字)范圍內(nèi)的某個(gè)地方,具體取決于有多少礦工同時(shí)競(jìng)爭(zhēng)解決這個(gè)問題。
回想一下,SHA-256 的輸出只是一個(gè)數(shù)字。礦工的目標(biāo)是獲取當(dāng)前區(qū)塊的頭部,向其添加一個(gè)稱為nonce的隨機(jī)數(shù),并計(jì)算其哈希值。哈希的這個(gè)數(shù)值必須小于目標(biāo)值。這里的所有都是它的。但說起來容易做起來難。
回想一下 SHA-256 的第一個(gè)屬性:哈希函數(shù)的輸入總是會(huì)產(chǎn)生相同的輸出。因此,如果礦工拿到塊頭,對(duì)其進(jìn)行哈希處理,并意識(shí)到哈希值不小于目標(biāo)值,他們將不得不以某種方式更改輸入,以便嘗試找到低于目標(biāo)值的哈希值。
這就是nonce的用武之地。
礦工在塊頭中添加一個(gè)數(shù)字(從 0 開始),稱為nonce,并對(duì)該值進(jìn)行哈希處理。如果哈希值不小于目標(biāo)值,礦工將隨機(jī)數(shù)加 1,再次將其添加到塊頭,并對(duì)更改后的值進(jìn)行哈希處理。這個(gè)過程不斷重復(fù),直到找到小于目標(biāo)值的哈希值。
采礦示例
這是組成第一個(gè)塊頭的粗略近似值:
- 創(chuàng)世區(qū)塊中交易的默克爾根:
Merkle Root:
4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b
- 第一個(gè)已知的比特幣版本:
0.1.0
- 區(qū)塊的時(shí)間戳:
2009–01–03 18:15:05
- 目標(biāo)(這也是最高的目標(biāo)):
Target:
0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
- 沒有前一個(gè)區(qū)塊哈希——這是第一個(gè)區(qū)塊,所以這是一個(gè)獨(dú)特的案例
將其組件添加在一起后的最終塊頭:

讓我們使用這個(gè)大標(biāo)題并計(jì)算雙哈希:
SHA-256 of header:
7d80bd12dfdccbdde2c41c9f406edfc05afb3320f5affc4f510b05a3394e1c91
SHA-256 of the previous result (final result):
c5aa3150f61b752c8fb39525f911981e2f9982c8b9bc907c73914585ad2ef12b
當(dāng)轉(zhuǎn)換為以 10 為底時(shí),目標(biāo)和輸出哈希都是非常大的數(shù)字(請(qǐng)記住,長(zhǎng)度超過 67 位)。下面的 Python 函數(shù)并沒有嘗試在此處演示兩者的比較,而是處理比較:
def isBlockHashLessThanTarget(blockHash, target):
return int(blockHash, 16) < int(target, 16)
如果哈希值小于目標(biāo),則返回 True,否則返回 false。
這是我們的目標(biāo)和塊哈希的結(jié)果:

現(xiàn)在我們將原始?jí)K的十六進(jìn)制值加 1。這是以下結(jié)果:

注意由于添加了隨機(jī)數(shù),最后一個(gè)數(shù)字現(xiàn)在是 1
然后,我們運(yùn)行相同的散列算法并對(duì)這些更改的數(shù)據(jù)進(jìn)行比較。如果它不低于目標(biāo),請(qǐng)繼續(xù)重復(fù)。一旦找到成功的哈希,用于查找此解決方案的最新隨機(jī)數(shù)將保存在塊中。創(chuàng)世區(qū)塊上列出的隨機(jī)數(shù)是 2,083,236,893。
這意味著中本聰在找到一個(gè)可以接受的哈希之前迭代了這個(gè)過程超過 20 億次。我已經(jīng)為這個(gè)創(chuàng)世紀(jì)區(qū)塊挖掘過程編寫了一個(gè)小的 Python 實(shí)現(xiàn),可以在我的GitHub 上找到。
subhan-nadeem/bitcoin-mining-python
bitcoin-mining-python - 比特幣挖掘算法的 Python 實(shí)現(xiàn)
github.com
看看你需要多長(zhǎng)時(shí)間才能成功挖掘創(chuàng)世區(qū)塊!
警告:extraNonce
塊頭中的 nonce 值存儲(chǔ)為 32 位數(shù)字。這意味著任何人能夠達(dá)到的最高隨機(jī)數(shù)是232(大約 40 億)。經(jīng)過 40 億次迭代,nonce 耗盡,如果沒有找到解決方案,礦工再次陷入困境。
對(duì)此的解決方案是在coinbase(區(qū)塊的交易內(nèi)容,存儲(chǔ)為 merkle 樹)中添加一個(gè)稱為extraNonce 的字段。這個(gè) extraNonce 的大小僅受區(qū)塊本身大小的限制,因此只要區(qū)塊大小在協(xié)議限制范圍內(nèi),它就可以像礦工希望的那樣大。
如果隨機(jī)數(shù)的所有 40 億個(gè)可能值都用完,則將額外的隨機(jī)數(shù)添加并遞增到coinbase。計(jì)算新的默克爾根和隨后的新塊頭,并再次迭代隨機(jī)數(shù)。重復(fù)此過程,直到找到足夠的散列。
最好在nonce用完之前避免添加extraNonce,因?yàn)閷?duì) extraNonce 的任何更改都會(huì)更改 merkle 樹。這需要額外的計(jì)算才能向上傳播更改,直到計(jì)算出 merkle 樹的新根。
礦工獎(jiǎng)勵(lì)
以最快的速度成功發(fā)布區(qū)塊的礦工將獲得憑空創(chuàng)造的全新比特幣獎(jiǎng)勵(lì)。該獎(jiǎng)勵(lì)目前為 12.5 BTC。這些比特幣是如何產(chǎn)生的?
每個(gè)礦工只需在他們的區(qū)塊中添加一個(gè)新的輸出交易,在開始開采該區(qū)塊之前將 12.5 個(gè)比特幣歸屬于自己。網(wǎng)絡(luò)協(xié)議將在接收到新驗(yàn)證的塊時(shí)接受此特殊交易為有效。這種特殊事務(wù)稱為生成事務(wù)。礦工有責(zé)任在挖掘之前將此交易添加到區(qū)塊中。至少有一個(gè)案例是礦工在挖一個(gè)區(qū)塊之前忘記將獎(jiǎng)勵(lì)添加到交易中,有效地銷毀了 12.5 BTC!
驗(yàn)證工作量證明
假設(shè)我們的礦工發(fā)現(xiàn)了一個(gè)小于目標(biāo)的哈希值。該礦工所要做的就是將具有原始六個(gè)組件的挖掘塊發(fā)布到任何連接的節(jié)點(diǎn)。接收區(qū)塊的這個(gè)節(jié)點(diǎn)將首先驗(yàn)證交易集,確保所有交易都是有效的(例如,所有交易都經(jīng)過適當(dāng)?shù)暮灻⑶矣矌挪粫?huì)被重復(fù)使用和/或無中生有)。
然后,它將簡(jiǎn)單地對(duì)塊頭進(jìn)行雙重哈希?,并確保該值低于塊包含的目標(biāo)值。一旦該塊被認(rèn)為有效,新節(jié)點(diǎn)將繼續(xù)在網(wǎng)絡(luò)上傳播該塊,直到每個(gè)節(jié)點(diǎn)都有一個(gè)最新的分類帳。
如您所見,任何給定節(jié)點(diǎn)都可以輕松驗(yàn)證新發(fā)布的塊。然而,向網(wǎng)絡(luò)發(fā)布一個(gè)有效的區(qū)塊需要大量的計(jì)算能力(因此,電力和時(shí)間)。這種不對(duì)稱性使網(wǎng)絡(luò)得到保護(hù),同時(shí)允許希望在網(wǎng)絡(luò)上進(jìn)行經(jīng)濟(jì)活動(dòng)的個(gè)人以相對(duì)無縫的方式進(jìn)行。
出塊時(shí)間和調(diào)整目標(biāo)
當(dāng)?shù)谝慌V工開始挖礦時(shí),他們每個(gè)人都監(jiān)控出塊時(shí)間。每個(gè)比特幣區(qū)塊都有 10 分鐘的固定區(qū)塊時(shí)間。這意味著,鑒于網(wǎng)絡(luò)上當(dāng)前的計(jì)算能力(網(wǎng)絡(luò)哈希率)水平,節(jié)點(diǎn)總是希望平均每 10 分鐘產(chǎn)生一次新驗(yàn)證的塊。我們可以合理地期望在 10 分鐘內(nèi)生成塊,因?yàn)樵诮o定網(wǎng)絡(luò)哈希率的情況下,找到塊的概率是已知的。
例如,讓我們以比特幣中存在的最簡(jiǎn)單的目標(biāo):創(chuàng)世塊。任何單個(gè)散列小于最簡(jiǎn)單目標(biāo)的概率是 232 中的 1。這是超過四十億分之一。因此,我們可以合理地期望有人運(yùn)行 232 次挖掘問題迭代以找到合適的哈希值。網(wǎng)絡(luò)上的節(jié)點(diǎn)預(yù)計(jì)每 10 分鐘將在網(wǎng)絡(luò)上的所有礦工中運(yùn)行 40 億次這樣的迭代。
如果在大樣本量的塊中,塊開始出現(xiàn)的速度超過 10 分鐘,這非常清楚地表明網(wǎng)絡(luò)上的節(jié)點(diǎn)正在以比 10 分鐘快得多的速度迭代 40 億個(gè)哈希。這種情況促使每個(gè)節(jié)點(diǎn)根據(jù)網(wǎng)絡(luò)功率的增加(或減少)按比例調(diào)整目標(biāo),以確保每 10 分鐘繼續(xù)出塊。
實(shí)際上,網(wǎng)絡(luò)上的節(jié)點(diǎn)監(jiān)控2016個(gè)區(qū)塊的區(qū)塊時(shí)間,精確到兩周。每?jī)芍埽瑢⒖偝鰤K時(shí)間與預(yù)期出塊時(shí)間(即 20160 分鐘)進(jìn)行比較。
要獲得新的目標(biāo),只需將現(xiàn)有目標(biāo)乘以過去兩周的總實(shí)際出塊時(shí)間的比率即可得到預(yù)期出塊時(shí)間。這將根據(jù)網(wǎng)絡(luò)上進(jìn)入或退出計(jì)算能力的數(shù)量按比例調(diào)整目標(biāo)。

計(jì)算新目標(biāo)的公式,每個(gè)比特幣節(jié)點(diǎn)每 20160 分鐘(兩周)運(yùn)行一次
出塊時(shí)間和輕松計(jì)算找到有效塊的概率的能力使節(jié)點(diǎn)可以輕松監(jiān)控和確定網(wǎng)絡(luò)上的總算力并調(diào)整網(wǎng)絡(luò)。無論向網(wǎng)絡(luò)添加多少計(jì)算能力或增加速度有多快,平均出塊時(shí)間將始終保持在 10 分鐘。目前網(wǎng)絡(luò)上的總哈希率為每秒 28.27 exahash。即每秒在網(wǎng)絡(luò)上的所有計(jì)算機(jī)上運(yùn)行28.27 x 101?哈希。